
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <assert.h>
#include <android/log.h>

#include "importgl.h"

#include "app.h"
#include "cams.h"
#include "utils.h"
#include "jade.h"


// Total run length is 20 * camera track base unit length (see cams.h).
#define RUN_LENGTH  (20 * CAMTRACK_LEN)
#undef PI
#define PI 3.1415926535897932f
#define RANDOM_UINT_MAX 65535



// Capped conversion from float to fixed.
static long floatToFixed(float value)
{
    if (value < -32768) value = -32768;
    if (value > 32767) value = 32767;
    return (long)(value * 65536);
}

#define FIXED(value) floatToFixed(value)


static long sStartTick = 0;
static long sTick = 0;

static int  action_idx = 0;


//static Texture *texture = NULL;
static jade_model_t *model_triangle = NULL;

///////////////////////////////////////////////////////////////////////////////
//OpenGL App

void gluPerspective(GLfloat fovy, GLfloat aspect,
                           GLfloat zNear, GLfloat zFar)
{
    GLfloat xmin, xmax, ymin, ymax;

    ymax = zNear * (GLfloat)tan(fovy * PI / 360);
    ymin = -ymax;
    xmin = ymin * aspect;
    xmax = ymax * aspect;

    glFrustumx((GLfixed)(xmin * 65536), (GLfixed)(xmax * 65536),
               (GLfixed)(ymin * 65536), (GLfixed)(ymax * 65536),
               (GLfixed)(zNear * 65536), (GLfixed)(zFar * 65536));
}

/* Following gluLookAt implementation is adapted from the
 * Mesa 3D Graphics library. http://www.mesa3d.org
 */
void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez,
	              GLfloat centerx, GLfloat centery, GLfloat centerz,
	              GLfloat upx, GLfloat upy, GLfloat upz)
{
    GLfloat m[16];
    GLfloat x[3], y[3], z[3];
    GLfloat mag;

    /* Make rotation matrix */

    /* Z vector */
    z[0] = eyex - centerx;
    z[1] = eyey - centery;
    z[2] = eyez - centerz;
    mag = (float)sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
    if (mag) {			/* mpichler, 19950515 */
        z[0] /= mag;
        z[1] /= mag;
        z[2] /= mag;
    }

    /* Y vector */
    y[0] = upx;
    y[1] = upy;
    y[2] = upz;

    /* X vector = Y cross Z */
    x[0] = y[1] * z[2] - y[2] * z[1];
    x[1] = -y[0] * z[2] + y[2] * z[0];
    x[2] = y[0] * z[1] - y[1] * z[0];

    /* Recompute Y = Z cross X */
    y[0] = z[1] * x[2] - z[2] * x[1];
    y[1] = -z[0] * x[2] + z[2] * x[0];
    y[2] = z[0] * x[1] - z[1] * x[0];

    /* mpichler, 19950515 */
    /* cross product gives area of parallelogram, which is < 1.0 for
     * non-perpendicular unit-length vectors; so normalize x, y here
     */

    mag = (float)sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
    if (mag) {
        x[0] /= mag;
        x[1] /= mag;
        x[2] /= mag;
    }

    mag = (float)sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
    if (mag) {
        y[0] /= mag;
        y[1] /= mag;
        y[2] /= mag;
    }

#define M(row,col)  m[col*4+row]
    M(0, 0) = x[0];
    M(0, 1) = x[1];
    M(0, 2) = x[2];
    M(0, 3) = 0.0;
    M(1, 0) = y[0];
    M(1, 1) = y[1];
    M(1, 2) = y[2];
    M(1, 3) = 0.0;
    M(2, 0) = z[0];
    M(2, 1) = z[1];
    M(2, 2) = z[2];
    M(2, 3) = 0.0;
    M(3, 0) = 0.0;
    M(3, 1) = 0.0;
    M(3, 2) = 0.0;
    M(3, 3) = 1.0;
#undef M
    {
        int a;
        GLfixed fixedM[16];
        for (a = 0; a < 16; ++a)
            fixedM[a] = (GLfixed)(m[a] * 65536);
        glMultMatrixx(fixedM);
    }

    /* Translate Eye to Origin */
    glTranslatex((GLfixed)(-eyex * 65536),
                 (GLfixed)(-eyey * 65536),
                 (GLfixed)(-eyez * 65536));
}


///////////////////////////////////////////////////////////////////////////////
//Camera

void jade_camera_glulookat () {

    gluLookAt(0.0f, 0.0f, 30.0f, 0.0f, 0.0f, 0.0f,
	          0.0f, 1.0f, 0.0f);

}

///////////////////////////////////////////////////////////////////////////////
//World

void jade_world_create (int width, int height, 
        GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha){

    glViewport(0, 0, width, height);
    gluPerspective(15, (float)width / height, 0.5f, 150);

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity();

    glClearColor(red, green, blue, alpha);
    
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glShadeModel(GL_SMOOTH);


    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //GL_FASTEST GL_NICEST

}

void jade_world_prepare_render(int width, int height)
{

///    glViewport(0, 0, width, height);
/*
    glClearColorx((GLfixed)(0.1f * 65536),
                  (GLfixed)(0.2f * 65536),
                  (GLfixed)(0.3f * 65536), 0x10000);
*/
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(15, (float)width / height, 0.5f, 150);
    //gluPerspective(60, (float)width / height, 1.0f, 1000);
    //gluPerspective(45, (float)width / height, 0.5f, 150);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

/*
    gluLookAt(0.0f, 0.0f, 30.0f, 0.0f, 0.0f, 0.0f,
	          0.0f, 1.0f, 0.0f);
*/
    jade_camera_glulookat ();
}



///////////////////////////////////////////////////////////////////////////////

// Called from the app framework.
void appInit(int width, int height)
{
    int a;
    jade_texture_t *texture = NULL; 

    jade_world_create (width, height, 0.5f, 0.5f, 0.5f, 0.0f);


    //triangle data
    GLfloat vertices0[9] = {
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        0.0f, 1.0f, 0.0f
    };
    GLfloat vertices1[9] = {
        0.0f, -1.0f, -1.0f,
        0.0f, -1.0f, 1.0f,
        0.0f, 1.0f, 0.0f
    };
    GLubyte colors[12] = {
        255, 0, 0, 0,
        0, 255, 0, 0,
        0, 0, 255 ,0
    };



    model_triangle = jade_model_create (2);

    //init first triangle
    jade_model_set_vertices (model_triangle, vertices0, 9 * sizeof(GLfloat), 0);
    jade_model_set_colors (model_triangle, colors, 12 * sizeof(GLubyte), 0);
    jade_model_set_triangle_num (model_triangle, 1, 0);

    //init second triangle
    jade_model_set_vertices (model_triangle, vertices1, 9 * sizeof(GLfloat), 1);
    jade_model_set_colors (model_triangle, colors, 12 * sizeof(GLubyte), 1);
    jade_model_set_triangle_num (model_triangle, 1, 1);

///    model->setPosition(0.0f, 0.0f, -5.0f);
///    model->setScale(5.0f, 5.0f, 5.0f);

  
}


// Called from the app framework.
void appDeinit()
{
    if (model_triangle != NULL)
        jade_model_destroy (model_triangle);
}

// Called from the app framework.
/* The tick is current time in milliseconds, width and height
 * are the image dimensions to be rendered.
 */
void appRender(long tick, int width, int height)
{
    if (sStartTick == 0)
        sStartTick = tick;
    if (!gAppAlive)
        return;

    // Actual tick value is "blurred" a little bit.
    sTick = (sTick + tick - sStartTick) >> 1;

    // Terminate application after running through the demonstration once.
    if (sTick >= RUN_LENGTH)
    {
        gAppAlive = 0;
        return;
    }

    // Prepare OpenGL ES for rendering of the frame.
    jade_world_prepare_render(width, height);

/*
    gluLookAt(0.0f, 0.0f, 30.0f,
	          0.0f, 0.0f, 0.0f,
	          0.0f, 1.0f, 0.0f);
*/

    jade_model_render (model_triangle);


}

void appSetModelTextureOffset (double x, double y, double z) {

}


void appSetModelRotate (double x, double y, double z) {

}
